/*
 * Created on 2004-11-19
 *
 * Copyright: Bluejay Networks Inc. & Inquiry Management Systems Ltd.  2004
 *
 * This software is the proprietary information of Bluejay Networks Inc. & 
 * Inquiry Management Systems Ltd.  
 * Use is subject to license terms.
 */
package com.ims.iaa.html;

import java.util.HashMap;

/**
 * @author ShengMeng Bai
 *
 * This class parser a tag, and you can get the attribute form a tag.
 */
public class TagAttributeParser {
	private String m_sTag;
	private String m_sTagName = "";
	private boolean m_bStartTag = true;
	private HashMap m_attribute;
	
	public TagAttributeParser(){
		m_attribute = new HashMap();
	}
	/**
	 * @param sTag, the tag must a complete tag, 
	 * 				start with '<' and end with '>'
	 * 
	 * @throws Exception, if the tag is bad-form html tag
	 */
	public TagAttributeParser(String sTag) throws Exception{
		m_attribute = new HashMap();
		Parse(sTag);
	}
	/**
	 * @param sTag, the tag must a complete tag, 
	 * 				start with '<' and end with '>'
	 * 
	 * @throws Exception, if the tag is bad-form html tag
	 */
	public void Parse(String sTag) throws Exception{
		m_sTagName = "";
		m_attribute.clear();
		
		if(sTag == null){
			throw new Exception("Can't parse null string.");
		}
		m_sTag = sTag.trim();
		if(m_sTag.charAt(0) != '<' ||
				sTag.charAt(sTag.length() - 1) != '>'){
				throw new Exception("The tag is bad-from tag, it must stat with '<' and end with '>'.");
			}
		if(m_sTag.length() < 3){//only "<>"
			throw new Exception("Can't parse <>.");
		}
		while(m_sTag.indexOf(" =") > -1){
			m_sTag = m_sTag.replaceAll(" =", "=");
		}
		Token();
	}
	/**
	 * Get the attribute's value.
	 * if the tag is <script src="www.sample.org">,
	 * getValue("SRC") or getValue("src") will return "www.sample.org"
	 * @param sAttribute, the attribute name
	 * @return the value, if the attribute exist, else null.
	 */
	public String getValue(String sAttribute){
		if(sAttribute == null){
			return null;
		}
		return (String)m_attribute.get(sAttribute.toLowerCase());
	}
	/**
	 * <script>, return "script"
	 * <SCRIPT>, return "SCRIPT"
	 * @return the lowercase tag name, if parse fail, return ""
	 */
	public String getTagName(){
		return m_sTagName;
	}
	/**
	 * <script>, return true
	 * </script>, return false
	 * @return true, if the tag don't start with '</', else false
	 */
	public boolean isStartTag(){
		return m_bStartTag;
	}
	
	private void Token() throws Exception{
		boolean bHasQutation1 = false;
		boolean bHasQutation2 = false;
		String sAtt = "";
		String sValue = "";
		boolean bHasTagName = false;
		boolean bHasAtt = false;
		
		int iIndex = 1;
		char cChar = m_sTag.charAt(iIndex);
		while(cChar != '>'){
			//++Get rid of blank
			while(cChar == ' ' || cChar == '\n' || cChar == '\r'){
				iIndex++;
				cChar = m_sTag.charAt(iIndex);
				if(cChar == '>'){
					return;
				}
			}
			//--Get rid of blank
			int iStart = iIndex;
			//++Find ' ' or '=' or '>'
			do{
				if(cChar == '\''){
					bHasQutation1 = !bHasQutation1;
				}
				if(cChar == '\"'){
					bHasQutation2 = !bHasQutation2;
				}
				iIndex++;
				cChar = m_sTag.charAt(iIndex);
			}while(!(cChar == ' '|| cChar == '\n' || cChar == '\r' ||//has blank
					(cChar == '=' && (!bHasAtt)) ||//has =
					cChar == '>') ||//is end
					bHasQutation1 || bHasQutation2);//has qutate
			//--Find ' ' or '=' or '>'
			if(cChar != '>'){
				String sGet = m_sTag.substring(iStart, iIndex);
				//get the tag name
				if(!bHasTagName){
					if(cChar != ' ' && cChar != '\n' && cChar != '\r'){
						throw new Exception("Bad-form tag, must have a tag name.");
					}
					m_sTagName = sGet.toLowerCase();
					bHasTagName = true;
				}else{
					//get the attribute
					if(!bHasAtt){
						if(cChar == '='){
							sAtt = sGet.toLowerCase();
							bHasAtt = true;
						}else{
							//++Add at 2004-12-10 by ShengMengBai
							sGet = sGet.toLowerCase();
							//--Add at 2004-12-10 by ShengMengBai
							//some attribute has default value
							if(sGet.equals("selected") || 
								sGet.equals("checked") || 
								sGet.equals("selected") ||
								sGet.equals("nohref") ||
								sGet.equals("noresize") ||
								sGet.equals("noshade") ||
								sGet.equals("nowrap") || 
								sGet.equals("compact") || 
								sGet.equals("declare") || 
								sGet.equals("defer") || 
								sGet.equals("readonly") || 
								sGet.equals("ismap") || 
								sGet.equals("multiple")){
								m_attribute.put(sGet, "true");
							}else{
								//++Add at 2004-12-10 by ShengMengBai
								m_attribute.put(sGet, "true");
								//--Add at 2004-12-10 by ShengMengBai
								//throw new Exception("Bad-form tag");
							}
						}
					}else{//get the value
						sValue = sGet;
						if(sValue.charAt(0) == '\'' || sValue.charAt(0) == '\"'){
							sValue = sValue.substring(1, sValue.length() - 1);
						}
						m_attribute.put(sAtt, sValue);
						bHasAtt = false;
					}
				}
			}else{
				if(bHasQutation1 || bHasQutation2){
					throw new Exception("Bad-form tag, the quote is unmatch.");
				}else{
					String sGet = m_sTag.substring(iStart, iIndex);
					if(!bHasTagName){
						m_sTagName = sGet.toLowerCase();
					}else{
						if(!bHasAtt){
							//some attribute has default value
							if(sGet.equals("selected") || 
								sGet.equals("checked") || 
								sGet.equals("selected") ||
								sGet.equals("nohref") ||
								sGet.equals("noresize") ||
								sGet.equals("noshade") ||
								sGet.equals("nowrap") || 
								sGet.equals("compact") || 
								sGet.equals("declare") || 
								sGet.equals("defer") || 
								sGet.equals("readonly") || 
								sGet.equals("ismap") || 
								sGet.equals("multiple")){
								m_attribute.put(sGet, "true");
							}else{
								//++Add at 2005-2-24 by ShengMengBai
								m_attribute.put(sGet, "true");
								//--Add at 2005-2-24 by ShengMengBai
								//throw new Exception("Bad-form tag");
							}
						}else{
							sValue = sGet;
							if(sValue.charAt(0) == '\'' || sValue.charAt(0) == '\"'){
								sValue = sValue.substring(1, sValue.length() - 1);
							}
							m_attribute.put(sAtt, sValue);
							bHasAtt = false;
						}
					}
				}
				return;
			}
			iIndex++;
			cChar = m_sTag.charAt(iIndex);
		}
	}
	public static void main(String[] args){
		try{
			TagAttributeParser obj =
				new TagAttributeParser("<frame src=\"englishframe-3.htm\" frameborder=\"NO\" scrolling=\"NO\" noresize>");
			System.out.println("Tag: " + obj.getTagName());
			System.out.println("att src: " + obj.getValue("SRC"));
			System.out.println("att test: " + obj.getValue("Test"));
			System.out.println("att No: " + obj.getValue("no"));
		}catch (Exception e){
			e.printStackTrace();
		}
	}
}
